package tool;

import java.io.File;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;


public class BaseDao {

	private static final String driver="com.mysql.jdbc.Driver";
	//定义连接对象
	private Connection connection=null;
	//定义预编译执行对象
	private PreparedStatement pStatement=null;
	//定义结果集对象
	private ResultSet rSet=null;
	//定义包
	private String url="jdbc:mysql://139.199.212.216:3306/xiaomidb?serverTimezone=Asia/Shanghai";
	//定义连接账号
	private String user="root";
	//定义密码
	private String password="yinfeizhou";
	/**连接数据库，使用那个数据库就自动创建实体类对象
	 * @throws ClassNotFoundException 
	 * @throws SQLException 
	 */
	Connection createConection() throws ClassNotFoundException, SQLException{
        Class.forName(driver);
        if(connection==null||connection.isClosed()){
            connection=DriverManager.getConnection(url, user, password);
        }
		return connection;
	}
	/**定义函数，关闭三大对象
	 */
	private void close()throws SQLException,ClassNotFoundException {
		if (null!=rSet) {
			rSet.close();
		}
		if (pStatement!=null) {
			pStatement.close();
		}
		if (connection!=null) {
			connection.close();
		}
	}
	/**根据数据库名得到所有表信息
	 * ClassNotFoundException
	 * SQLException
	 */
	public List getTableNameList() throws ClassNotFoundException,SQLException {
		this.createConection();
		/*此接口由驱动程序供应商实现，让用户了解 Database Management System (DBMS) 
		在与驱动程序（基于与其一起使用的 JDBCTM 技术（“JDBC 驱动程序”））
		相结合时的能力。不同的关系 DBMS 常常支持不同的功能，以不同方式实现这些
		功能，并使用不同的数据类型*/
		//定义一个对象，使其包含数据库表、支持的SQL语法、存储过程、此连接的功能等信息
		DatabaseMetaData dMetaData=connection.getMetaData();
		//获取可在给定类别中使用的表的描述。
		ResultSet resultSet=dMetaData.getTables(null, "%", "%", new String[] {"TABLE"});
		//定义表名单存储在list集合中
		List tableNameList=new ArrayList();
		while(resultSet.next()) {
			tableNameList.add(resultSet.getString("TABLE_NAME"));
		}
		return tableNameList;	
	}
	
	/**根据表名得到字段名
	 *  tableName
	 */
	public List getColumnNameList(String tableName) throws ClassNotFoundException,SQLException {
		DatabaseMetaData dMetaData=connection.getMetaData();
		//dMetaData.getColumns(目录,模式,表名模式、列名模式)
		//获取可在指定类别中使用的表列的描述
		ResultSet resultSet=dMetaData.getColumns(null, "%", tableName, "%");
		//定义字段名到列表中
		List columnNameList=new ArrayList();
		while (resultSet.next()) {
			columnNameList.add(resultSet.getString("COLUMN_NAME"));	
		}
		return columnNameList;
	}
	/**根据表名得到字段名属性
	 */
	public List<String> getColumnTypes(String tableName){
		List<String> columnTypes=new ArrayList<>();
		PreparedStatement pStatement=null;
		String sql="select * from "+ tableName;
		try {
			pStatement=connection.prepareStatement(sql);
			//结果集元数据
			ResultSetMetaData rData=pStatement.getMetaData();
			//表的列数
			int tableSize=rData.getColumnCount();
			for (int i = 0; i < tableSize; i++) {
				columnTypes.add(rData.getColumnTypeName(i+1));
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			if (pStatement!=null) {
				try {
					pStatement.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return columnTypes;
	}
	/**
	 * 用于创建相关文件目录
	 */
	public static boolean mkDirectory(String path) {
		//文件和目录路径名的抽象表示形式.用户界面和操作系统使用与系统相关的路径名字符串 来命名文件和目录
		File file=new File ("..");
		try {
			//通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例
			file=new File(path);
			//测试此抽象路径名表示的文件或目录是否存在
			if (!file.exists()) {
				//创建此抽象路径名指定的目录，包括所有必需但不存在的父目录
				return file.mkdirs();
			}else {
				return false;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			file=null;
		}
		return false;
	}
	/**
	 *创建执行对象，绑定参数，不执行语句
	 */
	private void createStatement(String sql,Object...objects ) throws ClassNotFoundException,SQLException {
		//连库
		this.createConection();
		//创建执行对象
		pStatement=connection.prepareStatement(sql);
		if (objects!=null) {
			//绑定参数
			for (int i = 0; i < objects.length; i++) {
				//绑定
				pStatement.setObject((i+1), objects[i]);
			}
		}
	}
	/**
     * 执行查询操作
	 */
	public <E>List<E> executeQuery(String sql, Object[] param, RowMapper<E> row)
			throws ClassNotFoundException,SQLException{
		// 创建预编译执行对象
					pStatement = createConection().prepareStatement(sql);
					// 给预编译对象添加参数
					bindParam(param);
					ResultSet rs = pStatement.executeQuery();
					// 将结果集ResultSet的数据，装载到集合中
					List<E> list = new ArrayList<E>();
					while (rs != null && rs.next()) {
						// 将结果集中的一行数据，转换成一个实体对象（调用接口的抽象方法，具体的代码在实现类中完成）
						E e = row.rowmap(rs);
						// 将实体对象添加到集合中
						list.add(e);
					}
					close();
					return list;

	}

    /**
     * 查询单行列值
     */
	public <E> E excuteQueryOne(String sql,Object[] param,RowMapper<E> row)throws SQLException,ClassNotFoundException{
            this.createStatement(sql,param);
            rSet=pStatement.executeQuery();
		    E e=null;
            if (rSet.next()){
				e =row.rowmap (rSet);
			}
			close();
            return e;
    }

    /**执行增删改操作，获取自增主键ID
     * @param sql
     * @param param
     * @return
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public int update(String sql,Object[] param) throws SQLException,ClassNotFoundException{
        try {
            pStatement=createConection().prepareStatement(sql);
            //绑点参数
            bindParam(param);
            return  pStatement.executeUpdate();
        } catch (SQLException e) {
        	e.printStackTrace();
            System.out.print("执行增删改失败");
        }  finally {
            close();
        }
        return 0;
    }
    /**将占位符绑定到预编译执行对象上
     * @param param
     * @throws SQLException
     */
    void bindParam(Object[] param) throws SQLException{
	    if (param!=null){
	        int i=1;
            for (Object o:
                param ) {
                pStatement.setObject(i,o);
                i++;
            }
        }
    }
}
